package com.sfy.auth.domain.service.impl;

import cn.dev33.satoken.secure.SaSecureUtil;
import cn.dev33.satoken.stp.SaTokenInfo;
import cn.dev33.satoken.stp.StpUtil;
import com.google.gson.Gson;
import com.sfy.auth.common.enums.AuthUserStatusEnum;
import com.sfy.auth.common.enums.IsDeletedFlagEnum;
import com.sfy.auth.domain.constants.AuthConstants;
import com.sfy.auth.domain.convert.AuthUserBoConverter;
import com.sfy.auth.domain.entity.AuthUserBO;
import com.sfy.auth.domain.redis.RedisUtil;
import com.sfy.auth.domain.service.AuthUserDomainService;
import com.sfy.auth.infra.basic.entity.*;
import com.sfy.auth.infra.basic.service.*;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

@Service
public class AuthUserDomainServiceImpl implements AuthUserDomainService {
    @Resource
    private AuthUserService authUserService;

    private String salt = "sfy";

    @Resource
    private AuthUserRoleService authUserRoleService;

    @Resource
    private AuthRoleService authRoleService;

    @Resource
    private AuthPermissionService authPermissionService;

    @Resource
    private AuthRolePremissionService authRolePremissionService;

    @Resource
    private RedisUtil redisUtil;

    private String authPermissionPrefix = "auth.permission";

    private String authRolePrefix = "auth.role";

    private static final String LOGIN_PREFIX = "loginCode";

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean register(AuthUserBO authUserBO) {
        //校验用户是否存在
        AuthUser exist = new AuthUser();
        exist.setUserName(authUserBO.getUserName());
        List<AuthUser> authUsers = authUserService.queryByConditionCount(exist);
        if (!authUsers.isEmpty()) {
            return true;
        }
        //不存在则继续创建
        AuthUser authUser = AuthUserBoConverter.INSTANCE.AuthUserBOTOtoAuthUser(authUserBO);
        if (StringUtils.isNotBlank(authUser.getPassword())) {
            authUser.setPassword(SaSecureUtil.md5BySalt(authUser.getPassword(), salt));
        }
        authUser.setStatus(AuthUserStatusEnum.OPEN.getCode());
        authUser.setIsDeleted(IsDeletedFlagEnum.UN_DELETED.getCode());
        Integer insert = authUserService.insert(authUser);
        //查询角色表中的id
        AuthRole authRole = new AuthRole();
        authRole.setRoleKey(AuthConstants.NORMAL_USER);
        AuthRole roleResult = authRoleService.queryByCondition(authRole);
        Long roleId = roleResult.getId();
        Long userId = authUser.getId();
        AuthUserRole authUserRole = new AuthUserRole();
        authUserRole.setUserId(userId);
        authUserRole.setRoleId(roleId);
        authUserRole.setIsDeleted(IsDeletedFlagEnum.UN_DELETED.getCode());
        //插入关联表
        authUserRoleService.insert(authUserRole);
        //写入redis中
        //写入角色
        String roleKey = redisUtil.buildKey(authRolePrefix, authUser.getUserName());
        List<AuthRole> roleList = new ArrayList<>();
        roleList.add(authRole);
        redisUtil.set(roleKey, new Gson().toJson(roleList));
        AuthRolePremission authRolePremission = new AuthRolePremission();
        authRolePremission.setRoleId(roleId);
        List<AuthRolePremission> rolePremissionList =
                authRolePremissionService.queryByCondition(authRolePremission);
        List<Long> permissionIdList = rolePremissionList.stream().
                map(AuthRolePremission::getPermissionId).collect(Collectors.toList());
        //根据roleid查权限
        List<AuthPermission> permissionList = authPermissionService.queryByRoleList(permissionIdList);
        String permissionKey = redisUtil.buildKey(authPermissionPrefix, authUser.getUserName());
        redisUtil.set(permissionKey, new Gson().toJson(permissionList));
        return insert > 0;
    }

    @Override
    public Boolean update(AuthUserBO authUserBO) {
        AuthUser authUser = AuthUserBoConverter.INSTANCE.AuthUserBOTOtoAuthUser(authUserBO);
        authUser.setStatus(AuthUserStatusEnum.OPEN.getCode());
        authUser.setIsDeleted(IsDeletedFlagEnum.UN_DELETED.getCode());
        Integer update = authUserService.update(authUser);
        //有任何更新都要与缓存进行同步
        return update > 0;
    }

    @Override
    public Boolean delete(AuthUserBO authUserBO) {
        AuthUser authUser = new AuthUser();
        authUser.setId(authUser.getId());
        authUser.setIsDeleted(IsDeletedFlagEnum.DELETED.getCode());
        Integer update = authUserService.update(authUser);
        //有任何更新都要与缓存进行同步
        return update > 0;
    }

    @Override
    public Boolean changes(AuthUserBO authUserBO) {
        AuthUser authUser = AuthUserBoConverter.INSTANCE.AuthUserBOTOtoAuthUser(authUserBO);
        authUser.setId(authUser.getId());
        authUser.setStatus(authUser.getStatus());
        Integer update = authUserService.update(authUser);
        //有任何更新都要与缓存进行同步
        return update > 0;
    }

    @Override
    public SaTokenInfo doLogin(String validCode) {
        String loginKey = redisUtil.buildKey(LOGIN_PREFIX, validCode);
        String openId = redisUtil.get(loginKey);
        if (StringUtils.isBlank(openId)) {
            return null;
        }
        AuthUserBO authUserBO = new AuthUserBO();
        authUserBO.setUserName(openId);
        this.register(authUserBO);
        StpUtil.login(openId);
        SaTokenInfo tokenInfo = StpUtil.getTokenInfo();
        return tokenInfo;
    }

    @Override
    public AuthUserBO getUserInfo(AuthUserBO authUserBO) {
        AuthUser authUser = new AuthUser();
        authUser.setUserName(authUserBO.getUserName());
        List<AuthUser> list = authUserService.queryByConditionCount(authUser);
        if (CollectionUtils.isEmpty(list)) {
            return new AuthUserBO();
        }
        AuthUser user = list.get(0);
        AuthUserBO res = AuthUserBoConverter.INSTANCE.AuthUserToAuthUserBO(user);
        return res;
    }
}
